package com.gamex.findit.battle;
import java.io.ByteArrayOutputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipelineCoverage;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;

import com.gamex.findit.HomeController;
import com.gamex.findit.service.BattleService;

/**
 * 소켓 서버 핸들러
 * @author james
 *
 */
@ChannelPipelineCoverage("one")
public class ServerHandler extends SimpleChannelHandler {
	
	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
	
	private BattleService battleService;
	
	public ServerHandler(BattleService battleService){
		this.battleService = battleService;
	}
	
	public BattleService getProcessService() {
		return battleService;
	}
	
	private Channel nhChannel;
	private int readDataLen = 1;
	private int totalLength = 0;
	boolean isReady =false;
	private String userId;
	private String clientId="";
	private String gameId;
	ByteArrayOutputStream bout = new ByteArrayOutputStream();
	
	@Override
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
		ChannelBuffer buf = (ChannelBuffer) e.getMessage();
		nhChannel = ctx.getChannel();
		
		while (buf.readable()) {
			bout.write(buf.readByte());
			if (readDataLen == 4) {
				totalLength = Integer.parseInt(new String(bout.toByteArray())) + 4;
			}
			
			if (readDataLen == totalLength) {
				processManager(new String(bout.toByteArray()), ctx);
				
				bout.reset();
				readDataLen = 0;
				totalLength = 0;
			}
			readDataLen++;
		}
	}
	
	/*
	 *  사용자 요청처리구간
	 */
	private void processManager(String receiveData,ChannelHandlerContext ctx) throws Exception {
		logger.info("[요청값 ]" + receiveData);
		String [] data = receiveData.split("\\|");
		String serviceType = data[1];
		
//		logger.info("[요청파라미터] ");
//		for(String d : data )logger.info("param : " + d);
//			logger.info("[요청파라미터]");
		
		if(serviceType.equals(FindItBattleService.REQ_WAITROOM_LISTEN)){
			logger.info("######## 대기자 정보조회 ######## ");
			String returnVal;
			userId =data[2];
			
			if(FindItBattleService.clientChannel.get(userId) == null){
				FindItBattleService.clientChannel.put(userId,ctx.getChannel());
			}
			
			try {
				returnVal = getProcessService().getWaitMemeber(userId);
				sendResponse(FindItBattleService.REQ_WAITROOM_LISTEN, returnVal, false);
				//0027|100|000|0||2|1058,1,1059,1 길이|서비스|
				// 000|0||2|1058,1,1059,1
			}finally{
				returnVal =null;
			}
		}else if(serviceType.equals(FindItBattleService.MAKE_GAME_ROOM)){
			logger.info("######## 게임룸 생성 : " + userId +"######## ");
			
			//방만들기 (캐릭터 전송)
			//대기자 리스트 삭제 하고 방을 구성해서 기다림
			 gameId = getProcessService().createGameRoom(userId);
			 sendResponse(FindItBattleService.MAKE_GAME_ROOM, "000|" +gameId, false);

		}else if(serviceType.equals(FindItBattleService.OUT_GAME_ROOM)){
			logger.info("######## 방 나가기 : " +userId +"GAME ID :" +data[2] + " ######## ");
			
			//방나가기 
			//방에서 자신을 삭제하고 대기자리스트에 인서트 
			gameId = data[2];
			clientId = data[3];

			getProcessService().outListen(userId);
			
			sendResponse(FindItBattleService.OUT_GAME_ROOM,"000",false);
			sendResponse(FindItBattleService.OUT_GAME_ROOM,"000",clientId);
				
			gameId="";
			clientId ="";
		}else if(serviceType.equals(FindItBattleService.JOIN_GAME_ROOM)){
			logger.info("######## 게임룸 참여  접속자 : " +userId +" ######## ");
			
			//방들어가기
			//방에 대기하는 회원수 체크후 2명일때 튕겨냄
			gameId = data[2];
			String checkYn =getProcessService().joinGameRoom(userId, gameId);
			clientId = checkYn.substring(1);
			logger.info("######## 게임룸 참여  상대방 : " +clientId +" ######## ");
			
			if(checkYn.substring(0,1).equals("Y")){
				sendResponse(FindItBattleService.JOIN_GAME_ROOM,"000|"+clientId,false);
				sendResponse(FindItBattleService.JOIN_GAME_ROOM,"000|"+userId,clientId);
			}else{
				sendResponse(FindItBattleService.JOIN_GAME_ROOM,"999",false);
			}
		}else if(serviceType.equals(FindItBattleService.READY_GAME_ROOM)){
			logger.info("######## 게임준비 완료  : " +userId +" ######## ");
			
			//게임준비
			getProcessService().readyGameRoom(userId, gameId);
			clientId = data[2];
			sendResponse(FindItBattleService.READY_GAME_ROOM,"000",false);
			sendResponse(FindItBattleService.READY_GAME_ROOM,"000|"+userId,clientId);
		}else if(serviceType.equals(FindItBattleService.INVITE_LISTEN_ROOM)){
			logger.info("######## 게임진행  : " +userId +" ######## ");
			
			clientId = data[2];
			sendResponse(FindItBattleService.INVITE_LISTEN_ROOM,"000",false);
			sendResponse(FindItBattleService.INVITE_LISTEN_ROOM,"000|"+data[3],clientId);
		}else if(serviceType.equals(FindItBattleService.INVITE_FRIEND)){
			logger.info("######## 친구초대  : " +userId +" ######## ");
			
			clientId = data[2];
			//현재 접속중인지
			Channel client = FindItBattleService.clientChannel.get(clientId);
			String checkYn =getProcessService().searchGame(clientId);
			if(client ==null){
				//접속종료
				sendResponse(FindItBattleService.INVITE_FRIEND,"900|"+ clientId,false);
			}else if(!checkYn.equals("Y")){
				sendResponse(FindItBattleService.INVITE_FRIEND,"911|"+ clientId,false);
			}else{
			//게임방에 있는지
				sendResponse(FindItBattleService.INVITE_FRIEND,"000",false);
				sendResponse(FindItBattleService.INVITE_FRIEND,"000|"+data[3],clientId);
				}
		}else if(serviceType.equals(FindItBattleService.LANKING_LOG_USR)){
			//게임승리 포인트 적립
			
		}
	}
	
    //전문생성
    private void sendResponse(String command,String doc ,boolean check){
    	byte [] result;
    	try{
    		result = String.format("%s%s%s%s%s",String.format("%04d",doc.length()+5),"|",command,"|",doc).getBytes();
    		ChannelBuffer buffer = ChannelBuffers.buffer(result.length);
			buffer.writeBytes(result);
			nhChannel.write(buffer);
//			logger.info("[응답] "+ new String(result));
			if(check)nhChannel.close();
    	}finally{
    		result =null;
    	}
    }
    
    private void sendResponse(String command,String doc ,String clientId){
    	byte [] result;
    	try{
    		result = String.format("%s%s%s%s%s",String.format("%04d",doc.length()+5),"|",command,"|",doc).getBytes();
			Channel client = FindItBattleService.clientChannel.get(clientId);
			if(client !=null && !client.equals("")){
				ChannelBuffer buffer = ChannelBuffers.buffer(result.length);
				buffer.writeBytes(result);
//				logger.info("[상대방 응답] "+ new String(result));
				client.write(buffer);
			}
			}finally{
    		result =null;
    	}
    }
    
	@Override
	public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
		logger.info("접속 종료  (" + userId +"):  " + ctx.getChannel().getRemoteAddress());
		
		if(gameId !=null && !gameId.equals("")){
			getProcessService().outGameRoom(gameId, userId);
		}
		
		if(clientId != null && !clientId.equals("")){
			sendResponse(FindItBattleService.OUT_GAME_ROOM,"000",clientId);
		}
		
		if(userId !=null && !userId.equals("")){
			getProcessService().outListen(userId);
			
			if(FindItBattleService.clientChannel.get(userId) !=null){
				FindItBattleService.clientChannel.remove(userId);
				//데이터베이스 삭제
			}
		}
		super.channelDisconnected(ctx, e);
	}
	
	@Override
	public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
		logger.info("접속자 COUNT" + FindItBattleService.clientChannel.size());
		super.channelConnected(ctx, e);
	}
	
	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
		if(gameId !=null && !gameId.equals("")){
			getProcessService().outGameRoom(gameId, userId);
		}
		if(userId !=null && !userId.equals("")){
			getProcessService().outListen(userId);
			if(FindItBattleService.clientChannel.get(userId) !=null)
				FindItBattleService.clientChannel.remove(userId);
		}
		
		logger.error("[에러] "+ e.toString());
		e.getCause();
		ctx.getChannel().close();
	}
	
	
}